<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.caishi.cn/cdn/vue@2.6.11"></script>
    <!-- 引入样式 -->
    <link rel="stylesheet" href="./element/index.css">
    <!-- 引入组件库 -->
    <script src="./element/index.js"></script>
    <script src="./echarts.min.js"></script>
    <title>接口监控</title>
    <script>
        Date.prototype.Format = function (fmt) {
            let o = {
                "M+": this.getMonth() + 1,
                "d+": this.getDate(),
                "H+": this.getHours(),
                "m+": this.getMinutes(),
                "s+": this.getSeconds(),
                "q+": Math.floor((this.getMonth() + 3) / 3),
                S: this.getMilliseconds(),
            };
            if (/(y+)/.test(fmt)) {
                fmt = fmt.replace(
                    RegExp.$1,
                    (this.getFullYear() + "").substr(4 - RegExp.$1.length)
                );
            }
            for (let k in o) {
                if (new RegExp("(" + k + ")").test(fmt)) {
                    fmt = fmt.replace(
                        RegExp.$1,
                        // @ts-ignore
                        RegExp.$1.length === 1
                            ? o[k]
                            : ("00" + o[k]).substr(("" + o[k]).length)
                    );
                }
            }
            return fmt;
        };

        class Fetch {
            static request(input, error) {
                return window.fetch(input.url, {
                    credentials: 'omit',
                    ...input,
                    headers: {
                        ...input.headers,
                        "cqvip-appid": "keray_dev",
                        "cqvipenv": "hd",
                        "cqvip-type": "sm2"
                    }
                })
                    .then(r => {
                        // 302重定向登录处理
                        if (/\/login/g.test(r.url)) {
                            location.href = r.url;
                            return Promise.reject();
                        }
                        return r;
                    })
                    .then((r) => this.json(r))
                    .then(r => !error ? this.check(r) : r);
            }
            static get(input, param, error) {
                if (typeof input === typeof '') {
                    input = param ? input + "?" : input;
                    if (param) {
                        for (let key in param) {
                            if (param[key] === undefined || param[key] === null || param[key] === '') {
                                continue;
                            }
                            input += `${key}=${param[key]}&`
                        }
                        input = input.substring(0, input.length - 1);
                    }
                } else {
                    input.url = param ? input.url + "?" : input.url;
                    if (param) {
                        for (let key in param) {
                            input.url += `${key}=${param[key]}&`
                        }
                        input.url = input.url.substring(0, input.url.length - 1);
                    }
                }

                input = input.url ? input : {
                    url: input
                };
                return this.request({
                    method: 'get',
                    ...input,
                }, error);
            }

            static post(input, param, method, error) {
                let formData = new FormData();
                for (let key in param) {
                    if (param[key] === undefined || param[key] === null || param[key] === '') {
                        continue;
                    }
                    formData.append(key, param[key]);
                }
                input = input.url ? input : {
                    url: input
                };
                return this.request({
                    method: method ? method : 'POST',
                    body: formData,
                    ...input
                }, error);
            }

            static postJson(input, data, error) {
                input = input.url ? input : {
                    url: input
                };
                return this.request({
                    method: 'POST',
                    body: JSON.stringify(data),
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    ...input
                }, error);
            }

            static put(input, param, error) {
                return this.post(input, param, 'PUT', error);
            }

            static delete(input, param, error) {
                return this.post(input, param, 'DELETE', error);
            }

            static fetchErrorMessage(e, message, o) {
                console.error(e);
                if (e.code === -1 && !o) {
                    layer.msg(message, { icon: 5 });
                } else {
                    layer.msg(e.message || "系统异常", { icon: 5 });
                }
            };
            static async flagPromise(fetchPromise, flag, errorMessage) {
                if (flag) {
                    this.flag[flag] = true;
                }
                return fetchPromise.then(r => r).catch(e => {
                    Fetch.fetchErrorMessage(e, errorMessage);
                    throw e;
                }).finally(() => {
                    if (flag) {
                        this.flag[flag] = false;
                    }
                })
            };

            static progress(input, param = {}, onProgress) {
                let formData = new FormData();
                for (let key in param) {
                    if (param[key] === undefined || param[key] === null) {
                        continue;
                    }
                    formData.append(key, param[key]);
                }
                let opts = {
                    body: formData,
                    ...input
                };
                return new Promise((resolve, reject) => {
                    let xhr = new XMLHttpRequest();
                    xhr.open(opts.method || 'POST', input.url || input);
                    for (let key in opts.headers || {}) {
                        xhr.setRequestHeader(key, opts.headers[key]);
                    }
                    xhr.onload = e => resolve(JSON.parse(e.target.responseText))
                    xhr.onerror = reject;
                    if (xhr.upload && onProgress) {
                        xhr.upload.onprogress = onProgress;
                    }
                    if ('onprogerss' in xhr && onProgress) {
                        xhr.onprogress = onProgress;
                    }
                    xhr.send(opts.body)
                })
            }

            static check(result) {
                if (result.code !== 200 && result.code !== 0) {
                    window.app.message(result.message);
                    return Promise.reject(result);
                }
                return result.data || result.object;
            }

            static json(response) {
                if (response.status >= 200 && response.status < 300) {
                    try {
                        return response.json();
                    } catch (e) {
                        throw e;
                    }
                } else if (response.status === 401) {

                }
                return Promise.reject({
                    code: -1,
                    data: null,
                    message: "HTTP-ERROR",
                    response
                });
            }
        }

    </script>
    <style>
        @media only screen and (max-width: 3840px),
        only screen and (max-device-width:3840px) {

            html,
            body {
                font-size: 48px;
            }
        }

        @media only screen and (max-width: 2560px),
        only screen and (max-device-width:2560px) {

            html,
            body {
                font-size: 32px;
            }
        }

        @media only screen and (max-width: 2048px),
        only screen and (max-device-width:2048px) {

            html,
            body {
                font-size: 25.6px;
            }
        }

        @media only screen and (max-width: 1920px),
        only screen and (max-device-width:1920px) {

            html,
            body {
                font-size: 24px;
            }
        }

        @media only screen and (max-width: 1768px),
        only screen and (max-device-width:1768px) {

            html,
            body {
                font-size: 22.1px;
            }
        }

        @media only screen and (max-width: 1680px),
        only screen and (max-device-width:1680px) {

            html,
            body {
                font-size: 21px;
            }
        }

        @media only screen and (max-width: 1600px),
        only screen and (max-device-width:1600px) {

            html,
            body {
                font-size: 20px;
            }
        }

        @media only screen and (max-width: 1440px),
        only screen and (max-device-width:1440px) {

            html,
            body {
                font-size: 18px;
            }
        }

        @media only screen and (max-width: 1366px),
        only screen and (max-device-width:1366px) {

            html,
            body {
                font-size: 17.75px;
            }
        }

        @media only screen and (max-width: 1280px),
        only screen and (max-device-width:1280px) {

            html,
            body {
                font-size: 16px;
            }
        }

        @media only screen and (max-width: 1200px),
        only screen and (max-device-width:1200px) {

            html,
            body {
                font-size: 23.04px;
            }
        }

        @media only screen and (max-width: 1024px),
        only screen and (max-device-width:1024px) {

            html,
            body {
                font-size: 19.6608px;
            }
        }


        /*布局*/

        * {
            /* font-family: 'Microsoft YaHei'; */
            box-sizing: border-box;
            padding: 0;
            margin: 0;
        }

        .marginAuto {
            margin: 0 auto !important;
        }

        .i-xy-center,
        .i-yx-center {
            display: inline-flex;
            align-items: center;
            justify-content: center;
        }

        .i-yx-center {
            flex-direction: column;
        }

        .xy-center,
        .yx-center {
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .yx-center {
            flex-direction: column;
        }

        .i-xy-between,
        .i-yx-between {
            display: inline-flex;
            align-items: center;
            justify-content: space-between;
        }

        .i-yx-between {
            flex-direction: column;
        }

        .xy-between,
        .yx-between {
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        .flexWarp {
            flex-wrap: wrap;
        }

        .yx-between {
            flex-direction: column;
        }

        .al-self-start {
            align-self: flex-start;
        }

        .jf-start {
            justify-content: flex-start;
        }

        .jf-end {
            justify-content: flex-end;
        }

        .al-start {
            align-items: flex-start;
        }

        .al-end {
            align-items: flex-end;
        }

        .al-str {
            align-items: stretch;
        }

        .auto-grow {
            flex-grow: 1;
        }

        .full-width {
            width: 100%;
        }

        .full-height {
            height: 100%;
        }

        .hidden {
            display: none;
        }

        .no-wrap-text {
            white-space: nowrap;
        }

        .one-wrap {
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .two-wrap {
            overflow: hidden;
            text-overflow: ellipsis;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
        }

        .three-wrap {
            overflow: hidden;
            text-overflow: ellipsis;
            display: -webkit-box;
            -webkit-line-clamp: 3;
            -webkit-box-orient: vertical;
        }

        .four-wrap {
            overflow: hidden;
            text-overflow: ellipsis;
            display: -webkit-box;
            -webkit-line-clamp: 4;
            -webkit-box-orient: vertical;
        }

        .third-wrap {
            overflow: hidden;
            text-overflow: ellipsis;
            display: -webkit-box;
            -webkit-line-clamp: 3;
            -webkit-box-orient: vertical;
        }

        .text-center {
            text-align: center;
        }

        .pointer {
            cursor: pointer;
        }

        .wait {
            cursor: wait;
        }

        .no-mouse {
            cursor: not-allowed;
        }

        .garden {
            border-radius: 50%;
        }


        /* 这个是设置a标签的默认状态去除下划线 */

        a {
            text-decoration: none;
        }


        /* 这个是设置a标签的访问过后的状态去除下划线 */

        a:visited {
            text-decoration: none;
        }


        /* 这个是设置a标签的鼠标覆盖状态去除下划线 */

        a:hover {
            text-decoration: none;
        }


        /* 这个是设置a标签的活跃状态去除下划线 */

        a:active {
            text-decoration: none;
        }


        /*其他*/

        .border-radius-box {
            border-radius: 0.5rem;
        }

        .bold {
            font-weight: bold;
        }

        .left-title {
            margin-right: 0.33rem;
        }

        .member-header {
            border-radius: 50%;
            overflow: hidden;
        }

        .fontSize5 {
            font-size: 0.5rem;
        }

        .fontSize53 {
            font-size: 0.53rem;
        }

        .fontSize58 {
            font-size: 0.58rem;
        }

        .fontSize67 {
            font-size: 0.67rem;
        }

        .fontSize75 {
            font-size: 0.75rem;
        }

        .fontSize76 {
            font-size: 0.76rem;
        }

        .fontSize83 {
            font-size: 0.83rem;
        }

        .fontSize92 {
            font-size: 0.92rem;
        }

        .fontSize1 {
            font-size: 1rem;
        }

        .fontSize125 {
            font-size: 1.25rem;
        }

        .fontSize15 {
            font-size: 1.5rem;
        }

        .p {
            line-height: 0.75rem;
        }

        .textCenter {
            text-align: center;
        }

        .textJustify {
            text-align: justify;
        }

        .FW600 {
            font-weight: 600;
        }

        .FW300 {
            font-weight: 300;
        }

        .bgColor666 {
            background: #666;
        }

        .flex {
            display: flex;
            flex-wrap: wrap;
        }

        .between {
            display: flex;
            justify-content: space-between;
        }

        .FW600 {
            font-weight: 600;
        }

        .padding-1rem {
            padding: 1rem;
        }

        .positionAbsolute {
            position: absolute
        }

        .positionRelative {
            position: relative
        }

        .radius04 {
            border-radius: 0.04rem;
        }

        .radius08 {
            border-radius: 0.08rem;
        }

        button {
            outline: none;
        }

        .select-none {
            user-select: none;
        }
    </style>

    <style>
        .ip-dialog {
            height: 100%;
            width: 100%;
            overflow-y: auto;
            display: flex;
            flex-wrap: wrap;
            justify-content: space-between;
            overflow-x: auto;
        }

        .ipecharts {
            width: 20rem;
            height: 20rem;
            margin-bottom: 3rem;
        }

        .second.ipecharts {
            width: 100%;
            height: 40rem;
        }

        .uri.ipecharts {
            width: 100%;
            height: 40rem;
        }

        .kb {
            position: fixed;
            z-index: 999;
            padding: 0.5rem;
            left: 0;
            top: 0;
            width: 100px;
            font-size: 12px;
            background-color: rgba(255, 255, 255, 0.7);
        }

        .kb .t {
            font-size: 15px;
        }

        .kb .s {
            color: green;
        }

        .kb .f {
            color: red;
        }

        .kb .r {
            color: rgb(144, 144, 14);
        }

        .ip-box {
            padding: 0 1vw;
            font-size: 12px;
        }

        .ip-box p {
            margin-top: 10px;
        }

        .speed-box {
            width: 100%;
            height: 30vh;
            min-height: 300px;
        }
    </style>
</head>

<body>
    <div id="app" class="yx-center app jf-start">
        <div class="xy-center flexWarp">
            <div v-for="item in rejectIps" class="xy-center" style="margin-top: 0.5rem">
                <div style="margin: 0 1rem 0 2rem;">ip:{{ item }} </div>
                <el-button size="mini" type="warning" @click="rejectIp(item, true)">解封</el-button>
            </div>
        </div>
        <div style="margin-top: 20px">
            <el-radio-group v-model="allTimeSpeed" size="small">
                <el-radio-button :label="1">1秒</el-radio-button>
                <el-radio-button :label="5">5秒</el-radio-button>
                <el-radio-button :label="10">10秒</el-radio-button>
                <el-radio-button :label="60">1分钟</el-radio-button>
                <el-radio-button :label="600">10分钟</el-radio-button>
                <el-radio-button :label="1800">30分钟</el-radio-button>
                <el-radio-button :label="3600">1小时</el-radio-button>
            </el-radio-group>
        </div>
        <div id="speed-box" class="speed-box"></div>
        <p>检索接口调用时间趋势</p>
        <div id="search-box" class="speed-box"></div>
        <div v-show="speedDialog" id="speed-box1" class="speed-box"></div>
        <div style="margin-top: 20px">
            <el-radio-group v-model="timeType" size="small" :disabled="ipListLoading">
                <el-radio-button :label="1">最近10秒</el-radio-button>
                <el-radio-button :label="2">最近30秒</el-radio-button>
                <el-radio-button :label="3">最近1分钟</el-radio-button>
                <el-radio-button :label="4">最近5分钟</el-radio-button>
                <el-radio-button :label="5">最近10分钟</el-radio-button>
                <el-radio-button :label="6">最近30分钟</el-radio-button>
                <el-radio-button :label="7">最近1小时</el-radio-button>
                <el-radio-button :label="8">最近1天</el-radio-button>
                <el-radio-button :label="9">最近1周</el-radio-button>
                <el-radio-button :label="10">最近1个月</el-radio-button>
                <el-radio-button :label="11">今日凌晨</el-radio-button>
            </el-radio-group>
        </div>
        <br />
        <el-table :data="ipRank" v-loading="ipListLoading" style="width: 100%">
            <el-table-column prop="_id" label="ip地址" width="140">
            </el-table-column>
            <el-table-column prop="cnt" label="访问量" min-width="100">
            </el-table-column>
            <el-table-column prop="time" label="平均用时" min-width="100">
            </el-table-column>
            <el-table-column prop="fail" label="失败次数" min-width="100">
            </el-table-column>
            <el-table-column prop="sl" label="成功率" min-width="100">
            </el-table-column>
            <el-table-column label="操作" width="200">
                <template slot-scope="scope">
                    <el-button size="mini" @click="ipDetail(scope.row)">详情</el-button>
                    <el-button size="mini" type="danger" @click="rejectIp(scope.row._id, false)">禁用ip</el-button>
                </template>
            </el-table-column>
        </el-table>
        <el-dialog title="提示" :visible.sync="ipDialogVisible" fullscreen width="90%" @opened="ipEchartsInit">
            <span slot="title"></span>
            <div class="ip-dialog">
                <div class="ipecharts" id="appid"></div>
                <div class="ipecharts" id="code"></div>
                <div class="ipecharts" id="duid"></div>
                <div class="ipecharts uri" id="uri"></div>
                <div class="ipecharts second" id="second"></div>
            </div>
        </el-dialog>
        <div class="kb xy-center jf-start flexWarp">
            <p class="t">TQPS:{{all.tq}}/s</p>
            <p class="s">SQPS:{{all.sq}}/s</p>
            <p class="f">FQPS:{{all.fq}}/s</p>
            <p class="r">RQPS:{{all.rq}}/s</p>
        </div>

        <div class="yx-center al-start ip-box full-width">
            <p>机构&作者检索次数剩余《400 限制500</p>
            <p v-for="item in objectSearchIp">
                <span>ip：{{item.ip}}</span>
                <span> cnt：{{item.cnt}}</span>
                <el-button size="mini" type="danger" @click="rejectIp(item.ip, false)">禁用ip</el-button>
            </p>
        </div>
        <div class="yx-center al-start ip-box full-width">
            <p>机构&作者获取对象次数剩余《200 限制300</p>
            <p v-for="item in objectDataIps">
                <span>ip：{{item.ip}}</span>
                <span> cnt：{{item.cnt}}</span>
                <el-button size="mini" type="danger" @click="rejectIp(item.ip, false)">禁用ip</el-button>
            </p>
        </div>
        <div class="yx-center al-start ip-box full-width">
            <p>期刊对象检索&获取次数剩余《50 限制100</p>
            <p v-for="item in journalObjectDataIps">
                <span>ip：{{item.ip}}</span>
                <span> cnt：{{item.cnt}}</span>
                <el-button size="mini" type="danger" @click="rejectIp(item.ip, false)">禁用ip</el-button>
            </p>
        </div>

        <div class="yx-center al-start ip-box full-width">
            <p>ip检索次数剩余《9000 限制10000</p>
            <p v-for="item in searchDataIps">
                <span>ip：{{item.ip}}</span>
                <span> cnt：{{item.cnt}}</span>
                <el-button size="mini" type="danger" @click="rejectIp(item.ip, false)">禁用ip</el-button>
            </p>
        </div>
    </div>
    <script>
        const val = localStorage.getItem("kkk");
        const host = "https://apiv3.cqvip.com";
        const app = new Vue({
            el: '#app',
            data() {
                return {
                    ipListLoading: false,
                    ipRank: [],
                    ipDetailData: [],
                    ipDialogVisible: false,
                    rejectIps: [],
                    objectDataIps: [],
                    searchDataIps: [],
                    journalObjectDataIps: [],
                    objectSearchIp: [],
                    all: {
                        tq: 0,
                        sq: 0,
                        fq: 0,
                        rq: 0,
                    },
                    speedDialog: false,
                    allTimeSpeed: 10,
                    timeType: val ? parseInt(val) : 3, // 1最近10秒 2最近30秒 3最近一分钟 4最近5分钟 5最近10分钟 6最近半小时 7最近一小时 8最近一天 9最近一周 10最近一个月
                }
            },
            watch: {
                timeType(val) {
                    localStorage.setItem("kkk", val)
                    this.loadData();
                },
                allTimeSpeed(allTimeSpeed) {
                    this.loadSpeedData(this.allTimeSpeed);
                    this.loadSearchSpeedData(this.allTimeSpeed);
                }
            },
            created() {
                this.loadData();
                this.loadRejectIp();
                this.loadQps();
                // this.loadObjectIpData();
                // this.loadSearchIpData();
                // this.loadJournalObjectIpData();
                this.loadSpeedData(this.allTimeSpeed);
                this.loadSearchSpeedData(this.allTimeSpeed);
            },
            methods: {
                loadSpeedData(speed) {
                    this.loadSpeedDataVersion = this.loadSpeedDataVersion || 0;
                    this.loadSpeedDataVersion++;
                    const version = this.loadSpeedDataVersion;
                    // 结束时间延后10秒
                    let et = parseInt(new Date().getTime() / 1000) - 10;
                    // 最大区间48小时   或者speed的100个区间
                    let st = et - Math.min(48 * 3600, speed * 100);
                    const echarData = [];
                    const w = () => {
                        const now = new Date().getTime();
                        Fetch.get(`${host}/api-statistics/ipuri-visit-rank`, {
                            start: new Date(st * 1000).Format("yyyy-MM-dd HH:mm:ss"),
                            end: new Date(et * 1000).Format("yyyy-MM-dd HH:mm:ss"),
                            speed
                        }).then(res => {
                            if (version !== this.loadSpeedDataVersion) return;
                            echarData.push(...res);
                            // echarData.splice(0, 1);
                            const ys = echarData.map(v => v.ALL);
                            let option = {
                                tooltip: {
                                    trigger: 'axis'
                                },
                                legend: {
                                },
                                grid: {
                                    left: '2%',
                                    right: '2%',
                                    bottom: '0%',
                                    containLabel: true
                                },
                                xAxis: {
                                    type: 'category',
                                    boundaryGap: false,
                                    show: false,
                                    data: echarData.map(v => `${new Date(v.st).Format("dd号HH:mm:ss")}-${new Date(v.et).Format("dd号HH:mm:ss")}`)
                                },
                                yAxis: [
                                    {
                                        type: 'value'
                                    },
                                    {
                                        type: 'value'
                                    }
                                ],
                                series: [
                                    {
                                        name: '总数',
                                        type: 'line',
                                        yAxisIndex: 1,
                                        data: ys.map(v => v.cnt)
                                    },
                                    {
                                        name: '成功',
                                        type: 'line',
                                        yAxisIndex: 1,
                                        data: ys.map(v => v.okCnt)
                                    },
                                    {
                                        name: '拒绝',
                                        type: 'line',
                                        yAxisIndex: 0,
                                        data: ys.map(v => v.rejectCnt)
                                    },
                                    {
                                        name: '失败',
                                        type: 'line',
                                        yAxisIndex: 0,
                                        data: ys.map(v => v.failCnt)
                                    },
                                ]
                            };
                            this.getEchart("speed-box").setOption(option);
                            this.getEchart("speed-box").on('click', ({ name }) => {
                                const ym = new Date().Format("yyyy-MM-")
                                const ns = name.replaceAll("号", " ").split("-").map(v => new Date(ym + v));
                                this.loadSpeedDataDialog(ns[0], ns[1])
                            });

                            const ft = new Date().getTime();
                            setTimeout(() => {
                                w();
                            }, speed * 1000 - (ft - now));
                        })
                        st = et;
                        et += speed;
                    }
                    w();
                },
                loadSearchSpeedData(speed) {

                    this.loadSpeedDataVersion1 = this.loadSpeedDataVersion1 || 0;
                    this.loadSpeedDataVersion1++;
                    const version = this.loadSpeedDataVersion1;
                    // 结束时间延后10秒
                    let et = parseInt(new Date().getTime() / 1000) - 10;
                    // 最大区间48小时   或者speed的100个区间
                    let st = et - Math.min(48 * 3600, speed * 100);
                    const echarData = [];
                    const w = () => {
                        const now = new Date().getTime();
                        Fetch.get(`${host}/api-statistics/visit-rank-detail`, {
                            start: new Date(st * 1000).Format("yyyy-MM-dd HH:mm:ss"),
                            end: new Date(et * 1000).Format("yyyy-MM-dd HH:mm:ss"),
                            speed,
                            ip: false,
                            value: "/advanceSearch"
                        }).then(res => {
                            if (version !== this.loadSpeedDataVersion1) return;
                            echarData.push(...res.list);
                            const ys = echarData.map(({ cntData }) => {
                                cntData.avgTime = parseInt(cntData.totalTime / cntData.totalCnt);
                                return cntData;
                            });
                            let option = {
                                tooltip: {
                                    trigger: 'axis'
                                },
                                legend: {
                                },
                                grid: {
                                    left: '2%',
                                    right: '2%',
                                    bottom: '0%',
                                    containLabel: true
                                },
                                xAxis: {
                                    type: 'category',
                                    boundaryGap: false,
                                    show: false,
                                    data: echarData.map(v => `${new Date(v.st).Format("dd号HH:mm:ss")}-${new Date(v.et).Format("dd号HH:mm:ss")}`)
                                },
                                yAxis: [
                                    {
                                        type: 'value'
                                    },
                                    {
                                        type: 'value'
                                    }
                                ],
                                series: [
                                    {
                                        name: '调用次数',
                                        type: 'line',
                                        yAxisIndex: 0,
                                        data: ys.map(v => v.totalCnt)
                                    },
                                    {
                                        name: '最大时间',
                                        type: 'line',
                                        yAxisIndex: 1,
                                        data: ys.map(v => v.maxTime)
                                    },
                                    {
                                        name: '最小时间',
                                        type: 'line',
                                        yAxisIndex: 1,
                                        data: ys.map(v => v.minTime)
                                    },
                                    {
                                        name: '平均时间',
                                        type: 'line',
                                        yAxisIndex: 1,
                                        data: ys.map(v => v.avgTime)
                                    }
                                ]
                            };
                            this.getEchart("search-box").setOption(option);
                            const ft = new Date().getTime();
                            setTimeout(() => {
                                w();
                            }, speed * 1000 - (ft - now));
                        })
                        st = et;
                        et += speed;
                    }
                    w();
                },
                loadSpeedDataDialog(startTime, endTime) {
                    if (this.loadSpeedDataDialogFlag) return;
                    this.loadSpeedDataDialogFlag = true;
                    this.speedDialog = true;
                    Fetch.get(`${host}/api-statistics/ipuri-visit-rank`, {
                        start: startTime.Format("yyyy-MM-dd HH:mm:ss"),
                        end: endTime.Format("yyyy-MM-dd HH:mm:ss"),
                        speed: 1,
                        onlyAll: false
                    }).then(res => {
                        const x = res.map(v => `${new Date(v.st).Format("dd号HH:mm:ss")}-${new Date(v.et).Format("dd号HH:mm:ss")}`);
                        // 找到所有的IP
                        var ips = new Set();
                        res.forEach(item => Object.keys(item).forEach(v => ips.add(v)));
                        ips.delete("st");
                        ips.delete("et");
                        ips.delete("ALL");
                        const seriesMap = {};
                        const series = [];
                        for (let ip of ips) {
                            seriesMap[ip] = {
                                name: ip,
                                type: 'line',
                                data: []
                            };
                            series.push(seriesMap[ip]);
                        }
                        for (let item of res) {
                            for (let ip of ips) {
                                const data = seriesMap[ip].data;
                                data.push((item[ip] || {}).cnt || 0);
                            }
                        }
                        let option = {
                            tooltip: {
                                trigger: 'axis'
                            },
                            grid: {
                                left: '2%',
                                right: '2%',
                                bottom: '0%',
                                containLabel: true
                            },
                            xAxis: {
                                type: 'category',
                                boundaryGap: false,
                                show: false,
                                data: x
                            },
                            yAxis: [
                                {
                                    type: 'value'
                                }
                            ],
                            series
                        };
                        console.log(option);
                        this.getEchart("speed-box1").setOption(option);
                        this.loadSpeedDataDialogFlag = false;
                    })
                },
                loadData() {
                    this.ipListLoading = true;
                    const nowDate = new Date();
                    const now = nowDate.getTime();
                    let before = now - 10 * 1000;
                    let end = now;
                    if (this.timeType === 1) before = now - 10 * 1000;
                    else if (this.timeType === 2) before = now - 30 * 1000;
                    else if (this.timeType === 3) before = now - 60 * 1000;
                    else if (this.timeType === 4) before = now - 5 * 60 * 1000;
                    else if (this.timeType === 5) before = now - 10 * 60 * 1000;
                    else if (this.timeType === 6) before = now - 30 * 60 * 1000;
                    else if (this.timeType === 7) before = now - 3600 * 1000;
                    else if (this.timeType === 8) before = now - 24 * 3600 * 1000;
                    else if (this.timeType === 9) before = now - 7 * 24 * 3600 * 1000;
                    else if (this.timeType === 10) before = now - 30 * 24 * 3600 * 1000;
                    else if (this.timeType === 11) {
                        before = nowDate.setHours(2, 0, 0, 0)
                        end = nowDate.setHours(5, 0, 0, 0)
                    }
                    const start = new Date(before).Format("yyyy-MM-dd HH:mm:ss");
                    end = new Date(end).Format("yyyy-MM-dd HH:mm:ss");
                    Fetch.get(`${host}/api-statistics/ipuri-visit`, {
                        start,
                        end,
                    }).then(res => {
                        this.ipRank = res.map(v => {
                            v.sl = ((1 - v.fail / v.cnt) * 100).toFixed(2) + "%";
                            v.time = (v.useTime / v.cnt).toFixed(2) + "ms";
                            v.min = start;
                            v.max = end;
                            v.loading = false;
                            return v;
                        });
                    }).finally(() => {
                        this.ipListLoading = false;
                    })
                },
                loadRejectIp() {
                    Fetch.get(`${host}/system/reject-ips`).then(res => {
                        this.rejectIps = res;
                    })
                },
                loadQps() {
                    const w = () => {
                        const now = new Date().getTime();
                        let before = now - 5 * 1000;
                        const start = new Date(before).Format("yyyy-MM-dd HH:mm:ss");
                        const end = new Date(now).Format("yyyy-MM-dd HH:mm:ss");
                        Fetch.get(`${host}/api-statistics/api-overview`, {
                            start,
                            end,
                        }).then(res => {
                            const all = res.filter(v => v.clientId === "ALL")[0];
                            this.all.tq = (all.totalCnt / 5).toFixed(2);
                            this.all.sq = (all.successCnt / 5).toFixed(2);
                            this.all.fq = (all.failCnt / 5).toFixed(2);
                            this.all.rq = (all.rejectCnt / 5).toFixed(2);
                        })
                        setTimeout(() => {
                            w();
                        }, 1000);
                    };
                    w();
                },
                loadObjectIpData() {
                    Fetch.get(`${host}/api-statistics/limit-qps-ip`, {
                        min: 200,
                        keyPrefix: "URL_QPS:objectDataIp:",
                    }).then(res => {
                        this.objectDataIps = res;
                    })
                },
                loadJournalObjectIpData() {
                    Fetch.get(`${host}/api-statistics/limit-qps-ip`, {
                        min: 50,
                        keyPrefix: "URL_QPS:journalDataIp:",
                    }).then(res => {
                        this.journalObjectDataIps = res;
                    })
                },
                loadSearchIpData() {
                    Fetch.get(`${host}/api-statistics/limit-qps-ip`, {
                        min: 9000,
                        keyPrefix: "QPS:search:",
                    }).then(res => {
                        this.searchDataIps = res;
                    })
                },
                ipDetail(row) {
                    row.loading = true;
                    Fetch.get(`${host}/api-statistics/list-detail`, {
                        start: row.min,
                        end: row.max,
                        value: row._id
                    }).then(res => {
                        this.ipDetailData = res;
                        this.ipDialogVisible = true;
                    }).finally(() => {
                        row.loading = false;
                    })
                },
                rejectIp(ip, remove) {
                    Fetch.post(`${host}/system/reject-ip`, {
                        ip,
                        remove
                    }).then(res => {
                        const i = this.rejectIps.indexOf(ip);
                        this.rejectIps.splice(i, 1)
                    })
                },
                message(msg) {
                    this.$message.error(msg);
                },
                ipEchartsInit() {
                    const { appid, code, duid, uri, second } = this.ipDetailData;
                    console.log(appid);
                    const func = (data, title, subTitle) => {
                        return {
                            title: {
                                text: title,
                                left: 'center'
                            },
                            tooltip: {
                                trigger: 'item',
                                formatter: '{a} <br/>{b} : {c} ({d}%)'
                            },
                            legend: {
                                orient: 'vertical',
                                left: 'left'
                            },
                            series: [
                                {
                                    name: subTitle,
                                    type: 'pie',
                                    radius: '50%',
                                    data: data.map(v => {
                                        return {
                                            value: v.cnt,
                                            name: v._id || "NULL"
                                        }
                                    }),
                                    emphasis: {
                                        itemStyle: {
                                            shadowBlur: 10,
                                            shadowOffsetX: 0,
                                            shadowColor: 'rgba(0, 0, 0, 0.5)'
                                        }
                                    }
                                }
                            ]
                        };
                    }

                    this.getEchart("appid").setOption(func(appid, "appid分布", "appid"));
                    this.getEchart("code").setOption(func(code, "错误code分布", "code"));
                    this.getEchart("duid").setOption(func(duid, "duid分布", "dui'd"));
                    this.getEchart("uri").setOption(func(uri.slice(0, 30), "uri分布", ""));
                    const x = [];
                    const y = [];
                    const y2 = [];
                    const ms = [];
                    let i = 0;
                    for (let k of Object.keys(second)) {
                        x.push(i++);
                        const m = second[k];
                        y.push(m.cnt);
                        y2.push(m.fail);
                        const msi = [];
                        for (let k1 of Object.keys(m.ms || {})) {
                            msi.push({ s: k1, v: m.ms[k1] });
                        }
                        msi.sort((v, v1) => v.v < v1.v ? 1 : -1);
                        // 前20毫秒
                        ms.push(msi.slice(0, 20));
                    }
                    const secondOptions = {
                        legend: {},
                        tooltip: {
                            trigger: 'axis',
                            showContent: false
                        },
                        dataset: {
                            source: [
                                ['i', ...x],
                                ['成功', ...y],
                                ['失败', ...y2]
                            ]
                        },
                        xAxis: { type: 'category' },
                        yAxis: { gridIndex: 0 },
                        grid: { top: '55%' },
                        series: [
                            {
                                type: 'line',
                                smooth: true,
                                seriesLayoutBy: 'row',
                                emphasis: { focus: 'series' }
                            },
                            {
                                type: 'line',
                                smooth: true,
                                seriesLayoutBy: 'row',
                                emphasis: { focus: 'series' }
                            },
                            {
                                type: 'pie',
                                id: 'pie',
                                radius: '30%',
                                center: ['50%', '25%'],
                                emphasis: {
                                    focus: 'self'
                                },
                                label: {
                                    formatter: '{b}ms: {@2012} ({d}%)'
                                },
                            }
                        ]
                    };
                    let myChart = this.getEchart("second")
                    myChart.on('updateAxisPointer', function (event) {
                        const xAxisInfo = event.axesInfo[0];
                        if (xAxisInfo) {
                            const index = xAxisInfo.value;
                            const data = ms[index];
                            myChart.setOption({
                                series: {
                                    id: 'pie',
                                    data: data.map(v => {
                                        return {
                                            value: v.v,
                                            name: v.s
                                        }
                                    }),
                                }
                            });
                        }
                    });
                    myChart.setOption(secondOptions);
                },
                getEchart(id) {
                    if (this[id]) return this[id];
                    this[id] = echarts.init(document.getElementById(id));
                    return this[id];
                }
            }
        })
        window.app = app;
    </script>

</html>